--[[
Name: oUF_cRefactored
Author: Sonora (The Dragonflight, US Kirin Tor)
Website & SVN: http://code.google.com/p/browniehelper/source/browse/#svn/trunk/oUF_cRefactored
License: GNU General Public License v3

A significant portion of the code appearing in the module was adapted from the
oUF_Caellian project (by Caellian):

http://www.wowinterface.com/downloads/info9974-oUF_Caellian.html
]]

--Identifiers
local function isUnitPet(self, unit)
    return self:GetAttribute('unitsuffix') == 'pet'
end

local function isRaidUnit(self, unit)
    return self:GetParent():GetName():match('oUF_Raid')
end

local function isPartyUnit(self, unit)
    --Bleh
    return not unit and not isRaidUnit(self, unit)
end

local function getUnit(self, unit)
    if unit then return unit
    elseif isUnitPet(self, unit) then return 'unitPet'
    elseif isPartyUnit(self, unit) then return 'partyUnit'
    elseif isRaidUnit(self, unit) then return 'raidUnit'
    else
        print("Unhandled unit type")
    end
end

--SetStyle dispatcher
local function callDec(dec, self, unit,config)
    if dec then dec(self, unit, config) end
end

function cRefactored.SetStyle(self, unit)
    --[[
    Handles switching from raidUnit -> partyUnit styling if GetNumRaidMembers() <= partyUnitStyleCuffoff
    --]]
    
    --Get the current configuration
    local config = cRefactored.getCurrentStyle()
    
    --Get the unit type
    local unitType = getUnit(self,unit)
    
    --[[
    Implementation issue:  frames drawn before GetNumPartyMembers() > partyUnitStyleCutoff are not 
    redrawn, so you end up with a mix of small and medium format frames.  Need a way to redraw all 
    frames when we pass the threshold...
	]]

    --Switch the unitType flag based on group size if needed
    local groupSize = max(GetNumRaidMembers(), GetNumPartyMembers())
    if unitType == 'raidUnit' and groupSize <= config.partyUnitStyleCutoff then unitType = 'partyUnit' 
    elseif unitType == 'partyUnit' and groupSize > config.partyUnitStyleCutoff then unitType = 'raidUnit'
    end
    
    --A little hack to let decorators check and see if they are on their first call of a styling round
    self.setStyleSession = {}
    
    --Apply all preStyle calls
    for i,dec in ipairs(config.preStyle) do callDec(dec,self,unit,config) end
    
    --Get the decorators for this unit type
    local decs = config.unitStyles[unitType]
    
    --Apply all optional decs in order
    for i,dec in ipairs(decs) do callDec(dec,self,unit,config) end
    
    --Apply all preStyle calls
    for i,dec in ipairs(config.postStyle) do callDec(dec,self,unit,config) end
    
    --Return self (part of the oUF spec?)
    return self
    
end

--Unit spawning
local function spawnUnits(config)

    oUF:Spawn('player', 'oUF_Player'):SetPoint(unpack(config.playerPosition))--'CENTER', UIParent, config.playerPosition.x, config.playerPosition.y)
    oUF:Spawn('target', 'oUF_Target'):SetPoint(unpack(config.targetPosition))--'CENTER', UIParent, config.targetPosition.x, config.targetPosition.y)

    oUF:Spawn('pet', 'oUF_Pet'):SetPoint('BOTTOMLEFT', oUF.units.player, 'TOPLEFT', 0, 13)
    oUF:Spawn('focus', 'oUF_Focus'):SetPoint('BOTTOMRIGHT', oUF.units.player, 'TOPRIGHT', 0, 13)
    oUF:Spawn('focustarget', 'oUF_FocusTarget'):SetPoint('BOTTOMLEFT', oUF.units.target, 'TOPLEFT', 0, 13)
    oUF:Spawn('targettarget', 'oUF_TargetTarget'):SetPoint('BOTTOMRIGHT', oUF.units.target, 'TOPRIGHT', 0, 13)

end

local function spawnParty(config)
    local party = oUF:Spawn('header', 'oUF_Party')
    party:SetPoint(unpack(config.partyPosition))
    party:SetAttribute('showParty', true)
    party:SetAttribute('yOffset', config.partyRowOffset)
    party:SetAttribute('template', 'oUF_cParty')
    oUF.headers['party'] = party
end

local function spawnRaid(config)
    local raid = {}
    for i = 1, NUM_RAID_GROUPS do
        local raidgroup = oUF:Spawn('header', 'oUF_Raid'..i)
        raidgroup:SetAttribute('groupFilter', tostring(i))
        raidgroup:SetAttribute('showRaid', true)
        raidgroup:SetAttribute('yOffSet', config.raidRowOffset)
        table.insert(raid, raidgroup)
        if(i==1) then
            raidgroup:SetPoint(unpack(config.raidPosition))
        end
    end
    oUF.headers['raid'] = raid
end

local function setupPartyToggle(config)
    local party, raid = oUF.headers.party, oUF.headers.raid

    local partyToggle = CreateFrame('Frame')
    partyToggle:RegisterEvent('PLAYER_LOGIN')
    partyToggle:RegisterEvent('RAID_ROSTER_UPDATE')
    partyToggle:RegisterEvent('PARTY_LEADER_CHANGED')
    partyToggle:RegisterEvent('PARTY_MEMBERS_CHANGED')
    partyToggle:SetScript('OnEvent', function(self)
        local config = cRefactored.getCurrentStyle()
        if(InCombatLockdown()) then
            self:RegisterEvent('PLAYER_REGEN_ENABLED')
        else
            local memberCount = GetNumRaidMembers()
            self:UnregisterEvent('PLAYER_REGEN_ENABLED')
            if(memberCount~=0) then
                party:Hide()
                for i,v in ipairs(raid) do v:Show() end

                --Set colLength according to the configuration (adjust based on the group size)
                local colLength = (memberCount <= config.partyUnitStyleCutoff and config.partyUnitStyleColLength or config.raidUnitStyleColLength)
                local yOffSet = (memberCount <= config.partyUnitStyleCutoff and config.partyRowOffset or config.raidRowOffset)
        
                raid[1]:SetAttribute('yOffSet', yOffSet)
        
                --Position raid frames accordingly
                for i = 2, NUM_RAID_GROUPS do
        
                    --If this group should start a new column
                    if (i-1) % colLength == 0 then
                        raid[i]:SetPoint('TOPLEFT', raid[i-colLength], 'TOPRIGHT', config.raidColOffset, 0)                        
                    else
                        raid[i]:SetPoint('TOPLEFT', raid[i-1], 'BOTTOMLEFT', 0, yOffSet)
                    end
            
                    raid[i]:SetAttribute('yOffSet', yOffSet)
            
                end
            else
                party:Show()
                for i,v in ipairs(raid) do v:Hide() end
            end
        end
    end)
end

--Initialization
local function oUF_init()

    cRefactored.reactor:start()

    oUF:RegisterStyle('cRefactored', cRefactored.SetStyle)
    oUF:SetActiveStyle('cRefactored')
    oUF.headers = {}
    
    local config = cRefactored.getCurrentStyle()
    
    spawnUnits(config)
    spawnParty(config)
    spawnRaid(config)
    
    setupPartyToggle(config)
    
end

oUF_init()
